package org.apache.ocean;

import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Date;

import org.apache.commons.lang.SerializationUtils;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang.builder.ReflectionToStringBuilder;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.lucene.document.Document;
import org.apache.ocean.database.DB;
import org.apache.ocean.util.StringWriter2;
import org.jdom.Element;

/**
 * 
 * @author jasonr
 */
public class TransactionRecord implements Comparable, CElement {
	public static final CLong SUCCESS = new CLong(1);
	public static final CLong FAILURE = new CLong(100);

	public static final String UPDATE = "update";
	public static final String ADD = "add";
	public static final String DELETE = "delete";

	@DB(primarykey = true)
	public TransactionID id;
	@DB(index=true)
	public TransactionID cellTransactionID;
	public CLong schemaVersion;
	public String masterID;
	public String shardID;
	@DB(index=true)
	public CLong documentID;
	public CLong version;
	public String type;
	public CLong updateTime;
	public Date dateCreated;
	public Date dateModified;
	@DB(type = "BLOB(1 M)", serialize = true)
	@XML(binary = true)
	private Document document;
	public CLong status; // result of transaction on the master
	public String message;
	@DB(type = "CLOB(100 K)")
	public String stackTrace;
	public CLong thisUpdateTime;
	public CLong thisStatus;
	public String thisMessage;
	@DB(type = "CLOB(100 K)")
	public String thisStackTrace;

	public String toString() {
		return ReflectionToStringBuilder.toString(this);
	}
  
	public Element toElement() throws Exception {
		return XMLUtil.reflectToElement("transactionrecord", this);
	}
	
	public static TransactionRecord toTransactionRecord(Element element) throws Exception {
		return (TransactionRecord) XMLUtil.reflectToObject(TransactionRecord.class, element);
	}

	public static class TransactionRecordTransform implements OceanXML.Transform {
		public Object call(Element element) throws Exception {
			return toTransactionRecord(element);
		}
	}

	public int compareTo(Object object) {
		TransactionRecord other = (TransactionRecord) object;
		return id.compareTo(other.id);
	}

	public IDVersion getIDVersion() {
		return new IDVersion(documentID, version, shardID);
	}

	public Document getDocument() {
		return document;
	}

	public void setDocument(InputStream input) {
		document = (Document) SerializationUtils.deserialize(input);
	}

	public void setDocument(byte[] bytes) {
		document = (Document) SerializationUtils.deserialize(bytes);
	}

	public void setDocument(Document document) {
		this.document = document;
	}

	public byte[] getDocumentBytes() {
		if (document == null)
			return null;
		return SerializationUtils.serialize(document);
	}

	public String toXML() throws Exception {
		StringWriter2 stringWriter = new StringWriter2(1024);
		PrintWriter writer = new PrintWriter(stringWriter);
		writer.print("<transaction ");
		if (id != null) {
			writer.print("id=\"");
			writer.print(id.toString());
			writer.print("\" ");
		}
		if (type != null) {
			writer.print("type=\"");
			writer.print(type);
			writer.print("\" ");
		}
		if (shardID != null) {
			writer.print("shardID=\"");
			writer.print(shardID);
			writer.print("\" ");
		}
		if (status != null) {
			writer.print("status=\"");
			writer.print(status);
			writer.print("\" ");
		}
		if (documentID != null) {
			writer.print("documentID=\"");
			writer.print(documentID.toString());
			writer.print("\" ");
		}
		if (version != null) {
			writer.print("version=\"");
			writer.print(version.toString());
			writer.print("\" ");
		}
		if (dateCreated != null) {
			writer.print("dateCreated=\"");
			writer.print(DateParser.formatRFC822(dateCreated));
			writer.print("\" ");
		}
		if (dateModified != null) {
			writer.print("dateModified=\"");
			writer.print(DateParser.formatRFC822(dateModified));
			writer.print("\"");
		}
		writer.println(">");
		if (message != null) {
			writer.println("<message>");
			writer.println(StringEscapeUtils.escapeXml(message));
			writer.println("</message>");
		}
		if (stackTrace != null) {
			writer.println("<stackTrace>");
			writer.println(StringEscapeUtils.escapeXml(stackTrace));
			writer.println("</stackTrace>");
		}
		writer.println("</transaction>");
		writer.flush();
		return stringWriter.toString();
	}

	public void setStackTrace(Throwable throwable) {
		if (throwable != null) {
			message = throwable.getMessage();
			stackTrace = ExceptionUtils.getFullStackTrace(throwable);
		}
	}

	public TransactionRecord() {
	}
}
